home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Modules / BackSpaceModules / Source / SchoolView / Thinker.m < prev   
Text File  |  1994-04-16  |  19KB  |  884 lines

  1. //    Thinker.m
  2. //
  3. //    This class is the brains behind the BackSpace app; it is the Application
  4. //    object's delegate, and it watches the system to determine when to
  5. //    initiate the screen saver mode.
  6. //
  7. //    You may freely copy, distribute, and reuse the code in this example.
  8. //    NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  9. //    fitness for any particular use.
  10.  
  11.  
  12. #import "Thinker.h"
  13. #import "BackWindow.h"
  14. #import "BackView.h"
  15. #import "SpaceView.h"
  16. #import "MySlider.h"
  17. #import "Password.h"
  18. #import "psfuncts.h"
  19.  
  20. #import <appkit/appkit.h>
  21. #import <objc/NXBundle.h>
  22.  
  23. // convert vertical blank time to milliseconds
  24. #define SEC2MS(x) ((x * 1000) + 20)
  25.  
  26. //#define SHOWITERATIONSPERSEC
  27.  
  28. #ifdef SHOWITERATIONSPERSEC
  29. unsigned iterations;
  30. BStimeval then, now, targetTime;
  31. #endif
  32.  
  33. static id _BSThinker;
  34.  
  35. id BSThinker()
  36. {    return _BSThinker;
  37. }
  38.  
  39.  
  40. @implementation Thinker
  41.  
  42. - appDidInit:sender
  43. {
  44.     const char *autoLaunch;
  45.     globalTier = BACKGROUNDTIER;
  46.     openAnother = YES;
  47.     _BSThinker = self;
  48.  
  49.     backZone = NXCreateZone(vm_page_size, vm_page_size, YES);
  50.  
  51.     NXSetRect(&windowRect, 475, 300, 500, 450);
  52.  
  53.     [NXApp getScreens:&screens count:&screenCount];
  54.  
  55.     [commonImageInspector getFrame: &inspectorFrame];
  56.     currentInspector = commonImageInspector;
  57.     
  58.     [self getViewType];
  59.     [self setVirtualViewIndexAndIncrement:NO];
  60.     [self getWindowType];
  61.  
  62.     [self getScreenSaverSetting];
  63.     [self getScreenLockerSetting];
  64.     [self getPrioritySetting];
  65.     [self getImageFile];
  66.     [self getHotCornerSetting];
  67.  
  68.     autoLaunch = NXGetDefaultValue([NXApp appName], "NXAutoLaunch");
  69.     if (strcmp(autoLaunch,"YES"))
  70.     {
  71.         [[windMatrix window] makeKeyAndOrderFront:self];
  72.         windowHasBeenDisplayed = YES;
  73.     }
  74.     else [NXApp hide:self];
  75.     
  76. #ifdef SHOWITERATIONSPERSEC
  77.     then = currentTimeInMs();
  78.     targetTime = then + 10000;
  79. #endif
  80.     
  81.     srandom(time(0));
  82.  
  83.     return self;
  84. }
  85.  
  86. - appDidHide:sender
  87. {
  88.     if (windowType != BACKWINDOW) [self removeTimer];
  89.     return self;
  90. }
  91.  
  92. - appDidUnhide:sender
  93. {
  94.     if (!windowHasBeenDisplayed)
  95.     {
  96.         [[windMatrix window] makeKeyAndOrderFront:self];
  97.         windowHasBeenDisplayed = YES;
  98.     }
  99.  
  100.     if (windowType != NOWINDOW) [self createTimer];
  101.     return self;
  102. }
  103.  
  104.  
  105.  
  106. // Pretty much a dummy function to invoke the step method.
  107.  
  108. void timedEntryFunction (DPSTimedEntry timedEntry, double timeNow, void *theObject)
  109. {    [(id)theObject doDistributorLoop];
  110. }
  111.  
  112. - createTimer
  113. {
  114.     if (!timerValid)
  115.     {
  116.         timerValid = YES;
  117.         timer = DPSAddTimedEntry(0.02, &timedEntryFunction, self, NX_BASETHRESHOLD);
  118.     }
  119.     return self;
  120. }
  121.  
  122. - removeTimer
  123. {
  124.     if (timerValid) DPSRemoveTimedEntry (timer);
  125.     timerValid = NO;
  126.     return self;
  127. }
  128.  
  129. - doDistributorLoop
  130. {
  131.     NXEvent dummyEvent;
  132.     
  133.     keepLooping = YES;
  134.     [spaceView lockFocus];
  135.     if ([spaceView respondsTo:@selector(didLockFocus)]) [spaceView didLockFocus];
  136.  
  137.     do {
  138.         [spaceView oneStep];
  139.         [spaceWindow flushWindow];
  140.         NXPing ();    // Synchronize postscript for smoother animation
  141.  
  142.         [spaceView oneStep];
  143.         [spaceWindow flushWindow];
  144.         NXPing ();    // Synchronize postscript for smoother animation
  145.  
  146. #ifdef SHOWITERATIONSPERSEC
  147.             iterations++;
  148.             if ((now = currentTimeInMs()) > targetTime)
  149.             {
  150.                 printf("BackSpace: %5.1f its/sec\n",
  151.                     (double)iterations*1000.0/(double)(now - then));
  152.                 iterations = 0;
  153.                 targetTime = now + 10000;
  154.                 then = now;
  155.             }
  156. #endif
  157.             
  158.        } while (timerValid && keepLooping &&
  159.             ([NXApp peekNextEvent:NX_ALLEVENTS into:&dummyEvent 
  160.                 waitFor:0 threshold:NX_BASETHRESHOLD] == NULL));
  161.  
  162.     [spaceView unlockFocus];
  163.     
  164.     return self;
  165.  
  166. }
  167.  
  168. - installSpaceViewIntoWindow:w
  169. {
  170.     NXRect cvrect;
  171.     int i;
  172.     id subviews, contentView;
  173.     
  174.     if (!w) return nil;
  175.     contentView = [w contentView];
  176.  
  177.     // get size of content view
  178.     [contentView getBounds:&cvrect];
  179.     
  180.     // remove old subviews, this is overkill really...
  181.     subviews = [contentView subviews];
  182.     for (i=([subviews count]-1); i>=0; i--)
  183.     {    [[subviews objectAt:i] removeFromSuperview];
  184.     }
  185.     
  186.     // install it into the window's content view
  187.     [contentView addSubview:spaceView];
  188.     [contentView setAutoresizeSubviews:YES];
  189.     [spaceView setAutosizing:NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE];
  190.  
  191.     // size the spaceview
  192.     [spaceView sizeTo:cvrect.size.width :cvrect.size.height];
  193.     
  194.     return self;
  195. }
  196.  
  197. - useNormalWindow
  198. {
  199.     int myBacking;
  200.     
  201.     spaceView = [self backView];
  202.     myBacking = [self backingTypeForView:spaceView];
  203.  
  204.     if (!normalWindow)
  205.     {
  206.         normalWindow = [[Window allocFromZone:backZone]
  207.             initContent:&windowRect style:NX_RESIZEBARSTYLE
  208.             backing:myBacking 
  209.             buttonMask:NX_CLOSEBUTTONMASK
  210.             defer:NO];
  211.         
  212.         [self setWindowTitle];
  213.         [normalWindow useOptimizedDrawing:YES];
  214.         [normalWindow setDynamicDepthLimit:YES]; //want window depth to match device!
  215.         [normalWindow setOneShot:YES];
  216.         [normalWindow setDelegate:self];
  217.         [normalWindow setBackgroundGray:NX_BLACK];
  218.     }
  219.  
  220.     spaceWindow = normalWindow;
  221.     [self installSpaceViewIntoWindow:spaceWindow];
  222.  
  223.     if ([spaceView respondsTo:@selector(setImage:)])
  224.         [spaceView setImage: image];
  225.     if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
  226.     [spaceWindow display];
  227.  
  228.     [spaceWindow makeKeyAndOrderFront:self];
  229.     
  230.     // need to do this so flushing always works!
  231.     // must do it late because kit does lazy window creation ie the PostScript
  232.     // window might not exist until you actually draw to it
  233.     
  234.     if (myBacking == NX_RETAINED)
  235.         [spaceWindow setBackingType:NX_RETAINED];
  236.     else [spaceWindow setBackingType:NX_BUFFERED];
  237.  
  238.     return self;
  239. }
  240.  
  241. - (int) backingTypeForView:aView
  242. {
  243.     if ([aView respondsTo:@selector(useBufferedWindow)] 
  244.         && [aView useBufferedWindow])
  245.         return NX_BUFFERED;
  246.     return NX_RETAINED;
  247. }
  248.  
  249. - useBackWindow:(int)tier
  250. {
  251.     NXRect r={{0, 0}};
  252.     int myBacking;
  253.     
  254.     [NXApp getScreenSize:&(r.size)];
  255.  
  256.     spaceView = [self backView];
  257.     myBacking = [self backingTypeForView:spaceView];
  258.     
  259.     [self createBigWindowIfNecessaryForView:spaceView];
  260.  
  261.     if (myBacking == NX_RETAINED)
  262.     {    spaceWindow = bigUnbufferedWindow;
  263.         tweakWindow([spaceWindow windowNum], tier);
  264.     }
  265.     else
  266.     {    spaceWindow = bigBufferedWindow;
  267.     }
  268.  
  269.     [self installSpaceViewIntoWindow:spaceWindow];
  270.  
  271.     if ([spaceView respondsTo:@selector(setImage:)])
  272.         [spaceView setImage: image];
  273.  
  274.     [spaceWindow placeWindow:&r];
  275.     if (myBacking == NX_BUFFERED) [spaceWindow display];
  276.  
  277.     [spaceWindow orderFront:self];
  278.     if (myBacking == NX_BUFFERED) tweakWindow([spaceWindow windowNum], tier);
  279.     else [spaceWindow display];
  280.  
  281.     if ([spaceView respondsTo:@selector(newWindow)]) [spaceView newWindow];
  282.  
  283.     return self;
  284. }
  285.  
  286. - createBigWindowIfNecessaryForView:aView
  287. {
  288.     NXRect r={{0, 0}};
  289.     int myBacking = [self backingTypeForView:aView];
  290.     
  291.     [NXApp getScreenSize:&(r.size)];
  292.  
  293.     if ((myBacking == NX_RETAINED) && !bigUnbufferedWindow)
  294.     {
  295.     
  296.         bigUnbufferedWindow = [[BackWindow allocFromZone:backZone]
  297.             initContent:&r style:NX_TOKENSTYLE
  298.             backing:NX_NONRETAINED buttonMask:0 defer:NO];
  299.  
  300.         [bigUnbufferedWindow useOptimizedDrawing:YES];
  301.  
  302.         [bigUnbufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK
  303.                | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
  304.                | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
  305.                | NX_CURSORUPDATEMASK)];
  306.         [bigUnbufferedWindow addToEventMask:NX_FLAGSCHANGEDMASK];
  307.         [bigUnbufferedWindow setBackgroundGray:NX_BLACK];
  308.     }
  309.  
  310.     if ((myBacking == NX_BUFFERED) && !bigBufferedWindow)
  311.     {
  312.  
  313.         bigBufferedWindow = [[BackWindow allocFromZone:backZone]
  314.             initContent:&r style:NX_TOKENSTYLE
  315.             backing:NX_BUFFERED buttonMask:0 defer:NO];
  316.  
  317.         [bigBufferedWindow useOptimizedDrawing:YES];
  318.  
  319.         [bigBufferedWindow removeFromEventMask:(NX_LMOUSEDOWNMASK
  320.                | NX_MOUSEMOVEDMASK | NX_LMOUSEDRAGGEDMASK
  321.                | NX_MOUSEENTEREDMASK | NX_MOUSEEXITEDMASK
  322.                | NX_CURSORUPDATEMASK)];
  323.  
  324.         [bigBufferedWindow addToEventMask:NX_FLAGSCHANGEDMASK];
  325.         [bigBufferedWindow setDynamicDepthLimit:YES]; //want window depth to match device!
  326.         [bigBufferedWindow setOneShot:YES];
  327.         [bigBufferedWindow setBackgroundGray:NX_BLACK];
  328.     }
  329.  
  330.     return self;
  331. }
  332.  
  333. - changeWindowType:sender
  334. {
  335.     [self changeWindowTypeAndRemember:YES];
  336.     return self;
  337. }
  338.  
  339. - changeWindowTypeAndRemember:(BOOL)rem
  340. {
  341.     char str[10];
  342.     int newWindowType;
  343.  
  344.     newWindowType = [windMatrix selectedRow];
  345.     if (newWindowType == windowType) return self;
  346.     
  347.     windowType = newWindowType;
  348.  
  349.     if (rem)
  350.     {
  351.         sprintf(str,"%1d", windowType);
  352.         NXWriteDefault([NXApp appName], "windowType", str);
  353.     }
  354.  
  355.     [spaceWindow orderOut:self];
  356.     
  357.     switch (windowType)
  358.     {
  359.         case NOWINDOW:
  360.             [self removeTimer];
  361.             break;
  362.         case NORMALWINDOW:
  363.             [self useNormalWindow];
  364.             [self createTimer];
  365.             break;
  366.         case BACKWINDOW:
  367.             [self useBackWindow: globalTier];
  368.             [self createTimer];
  369.             break;
  370.     }
  371.     
  372.     return self;
  373. }
  374.  
  375. - getWindowType
  376. {
  377.     int tWindowType = NORMALWINDOW;
  378.     const char *ptr;
  379.     int val;
  380.  
  381.     ptr = NXGetDefaultValue([NXApp appName], "windowType");
  382.     if (ptr)
  383.     {
  384.         sscanf(ptr,"%d",&val);
  385.         if (val >= 0 && val <= 2) tWindowType = val;
  386.     }
  387.     
  388.     [windMatrix selectCellAt:tWindowType :0];
  389.     [self changeWindowTypeAndRemember:NO];
  390.  
  391.     return self;
  392. }
  393.  
  394. - getScreenSaverSetting
  395. {
  396.     const char *ptr;
  397.     
  398.     if((evs = NXOpenEventStatus()) == 0)
  399.     {    perror("NXOpenEventStatus failed.");
  400.         exit(10);
  401.     }
  402.     
  403.     [self getDimBrightness:&dimBrightness];
  404.     
  405.     //in case the old dim brightness is somehow invalid, I reset it
  406.     if (dimBrightness > .25)
  407.     {
  408.         dimBrightness = .25;
  409.         [self _setDimBrightness:&dimBrightness];
  410.     }
  411.  
  412.     [screenSaver setState:0];
  413.     
  414.     ptr = NXGetDefaultValue([NXApp appName], "screenSaver");
  415.  
  416.     if (!ptr || !strcmp(ptr,"Off")) [self setScreenSaver:NO andRemember:NO];
  417.     else [self setScreenSaver:YES andRemember:NO];
  418.     
  419.     return self;
  420. }
  421.  
  422. - changeScreenSaverSetting:sender
  423. {
  424.     [self setScreenSaver:([screenSaver state])andRemember:YES];
  425.     return self;
  426. }
  427.  
  428. - setScreenSaver:(BOOL)val andRemember:(BOOL)rem
  429. {
  430.     [screenSaver setState:val];
  431.     screenSaverVal = val;
  432.     
  433.     if (val)
  434.     {
  435.         // turn it on...
  436.         [self calcDimTime];
  437.         if (rem) NXWriteDefault([NXApp appName], "screenSaver", "On");
  438.     }
  439.     else
  440.     {
  441.         // turn it off...
  442.         if (rem) NXRemoveDefault([NXApp appName], "screenSaver");
  443.     }
  444.     
  445.     return self;
  446. }
  447.  
  448. - calcDimTime
  449. {
  450.     double dimTime;
  451.     [self getDimTime :&dimTime];
  452.     
  453.     if (dimTime < 0) dimTime = .1;
  454.     
  455.     if (screenSaverVal && !doingSaver)
  456.     {
  457.         // printf("BackSpace calcDimTime: dims in %f seconds\n",dimTime);
  458.     
  459.         [self perform:@selector(maybeDoScreenSaver:)
  460.             with:self
  461.             afterDelay:SEC2MS(dimTime)
  462.             cancelPrevious:YES];
  463.     }
  464.             
  465.     return self;
  466. }
  467.  
  468. - maybeDoScreenSaver:sender
  469. {
  470.     NXEvent anEvent;
  471.     BOOL autoDimmed;
  472.  
  473.     // in case timed entry fires but user has killed screen saver
  474.     if (!screenSaverVal || doingSaver) return self;
  475.     
  476.     autoDimmed = NXAutoDimState(evs);
  477.     if (!autoDimmed)
  478.     {
  479.         [self calcDimTime];
  480.         return self;
  481.     }
  482.  
  483.     // The perform:afterDelay: method starts a timed entry to
  484.     // invoke maybeDoScreenSaver, so we are in a timed entry
  485.     // right now.  If we just jumped into doScreenSaver:, we
  486.     // would interrupt the doDistributorLoop method while
  487.     // it's still focused on the spaceView.     By posting an
  488.     // event, we force that loop to bail out so we can jump
  489.     // into the screen saver cleanly.
  490.     
  491.     keepLooping = NO;    // There was a bug related to this at one point.
  492.                         // I don't think it's necessary anymore.
  493.     anEvent.type = NX_APPDEFINED;
  494.     anEvent.data.compound.subtype = BSDOSAVER;
  495.     anEvent.ctxt = [NXApp context];
  496.     DPSPostEvent(&anEvent,0);
  497.     
  498.     return self;
  499. }
  500.  
  501. - applicationDefined:(NXEvent *)theEvent
  502. {
  503.     switch (theEvent->data.compound.subtype)
  504.     {
  505.     case BSDOSAVER:
  506.         [self doScreenSaver:self];
  507.         [self calcDimTime];            // reset to fire again
  508.         break;
  509.     case BSOPENFILE:
  510.         [self doDelayedOpenFile];
  511.         break;
  512.     default:
  513.         break;
  514.     }
  515.     return self;
  516. }
  517.  
  518. - showFakeScreenSaverAfterPause:sender
  519. {
  520.     usleep(250000);
  521.     return [self showFakeScreenSaver:sender];
  522. }
  523.  
  524. - showFakeScreenSaver:sender
  525. {
  526.     [self screenSaverMode];
  527.     NXSetAutoDimState(evs, YES);
  528.     [self doScreenSaver:self];
  529.     NXSetAutoDimState(evs, NO);
  530.     [self normalMode];            //usually not necessary
  531.     
  532.     // reset to fire again
  533.     [self calcDimTime];
  534.         
  535.     return self;
  536. }
  537.  
  538.  
  539. - doScreenSaver:sender
  540. {
  541.     int oldWindowType;
  542.     BOOL mouseOK, oldTimerValid;
  543.     BOOL ignoreMouseMovement = NO;
  544.     BOOL isHidden;
  545.     NXRect trackingRect;
  546.     NXPoint mouseLoc;
  547.     NXEvent dummyEvent;
  548.     BOOL passwordOK;
  549.     BOOL stoleActivation = NO;
  550.     int oldActiveApp = 0;
  551.         
  552.     // must be sure we don't enter on timed entry after faking saver
  553.     doingSaver = YES;
  554.     
  555.     isHidden = [NXApp isHidden];
  556.     if (isHidden)
  557.     {
  558.         [NXApp unhideWithoutActivation:self];
  559.     }
  560.  
  561.     if ([password isLocked])
  562.     {
  563.         oldActiveApp = [NXApp activateSelf:YES];
  564.         stoleActivation = YES;
  565.     }
  566.     
  567.     [self setVirtualViewIndexAndIncrement:YES];
  568.  
  569.     //save old window state
  570.     oldWindowType = [windMatrix selectedRow];
  571.  
  572.     globalTier = SAVERTIER;
  573.  
  574.     [self blackOutAllScreens];
  575.     
  576.     //background window on screen
  577.     [windMatrix selectCellAt:BACKWINDOW :0];
  578.     [self changeWindowTypeAndRemember:NO];
  579.     
  580.     //nuke timer so timed entry doesn't fire
  581.     oldTimerValid = timerValid;
  582.     [self removeTimer];
  583.  
  584.  
  585.     //set background window tier to SAVERTIER
  586.     if ([self backingTypeForView:spaceView] == NX_BUFFERED)
  587.     {
  588.         // make sure the one shot buffer really exists
  589.         //[spaceWindow display];    //xxx
  590.         if ([spaceWindow windowNum] <= 0) [spaceWindow display];
  591.         PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
  592.     }
  593.     else 
  594.     {
  595.         PSsetwindowlevel(SAVERTIER, [spaceWindow windowNum]);
  596.         [spaceView fillBoundsWithBlack];
  597.         [spaceView display];
  598.     }
  599.  
  600.     NXPing();
  601.     [self screenSaverMode];
  602.  
  603.     if ([spaceView respondsTo:@selector(enteredScreenSaverMode)])
  604.         [spaceView enteredScreenSaverMode];
  605.  
  606.     do {
  607.         //obscure cursor
  608.         PShidecursor();
  609.     
  610.         [spaceView lockFocus];
  611.         if ([spaceView respondsTo:@selector(didLockFocus)])
  612.             [spaceView didLockFocus];
  613.  
  614.  
  615.         if ([spaceView respondsTo:@selector(ignoreMouseMovement)])
  616.             ignoreMouseMovement = [spaceView ignoreMouseMovement];
  617.  
  618.         [spaceWindow getMouseLocation:&mouseLoc];
  619.         trackingRect.origin.x = mouseLoc.x - 100;
  620.         trackingRect.origin.y = mouseLoc.y - 100;
  621.         trackingRect.size.width = trackingRect.size.height = 200;
  622.     
  623.         do {
  624.             [spaceView oneStep];
  625.             [spaceWindow flushWindow];
  626.             NXPing();    // Synchronize postscript for smoother animation
  627.  
  628.             // note: window and view coordinates the same!
  629.             // so I don't have to convert to view coord system
  630.             if (ignoreMouseMovement) mouseOK = YES;
  631.             else
  632.             {
  633.                 [spaceWindow getMouseLocation:&mouseLoc];
  634.                 mouseOK = [spaceView mouse:&mouseLoc inRect:&trackingRect];
  635.             }
  636.         
  637.             [spaceView oneStep];
  638.             [spaceWindow flushWindow];
  639.             NXPing();    // Synchronize postscript for smoother animation
  640.  
  641.         } while (mouseOK && ([NXApp peekNextEvent:
  642.                                         (NX_MOUSEUPMASK|NX_KEYDOWNMASK)
  643.                                     into:&dummyEvent waitFor:0.0
  644.                                threshold:NX_BASETHRESHOLD] == NULL));
  645.     
  646.         [spaceView unlockFocus];
  647.     
  648.         //restore cursor
  649.         PSshowcursor();
  650.         
  651.         passwordOK = [password checkPassword: 
  652.             NXLocalString("Screen is locked.  Enter password to unlock:",0,0) 
  653.             randomPos:YES checkLock:YES withView:spaceView];
  654.  
  655.         if (!passwordOK) NXSetAutoDimState(evs, YES);
  656.  
  657.     } while (!passwordOK);
  658.  
  659.     if ([spaceView respondsTo:@selector(willExitScreenSaverMode)])
  660.         [spaceView willExitScreenSaverMode];
  661.  
  662.     NXSetAutoDimState(evs, NO);
  663.     [self normalMode];
  664.  
  665.     //background window tier to BACKGROUNDTIER
  666.     PSsetwindowlevel(BACKGROUNDTIER, [spaceWindow windowNum]);
  667.     globalTier = BACKGROUNDTIER;
  668.     
  669.     if (([self backingTypeForView:spaceView] != NX_BUFFERED) &&
  670.             oldWindowType == BACKWINDOW)
  671.         // this justs fixes a display bug for really lazy nonretained windows
  672.     {
  673.         [spaceView fillBoundsWithBlack];
  674.         [spaceView display];
  675.     }
  676.  
  677.     if (oldTimerValid)    [self createTimer];
  678.  
  679.     [self unBlackOutAllScreens];
  680.     
  681.     //restore old window state
  682.     [windMatrix selectCellAt:oldWindowType :0];
  683.     [self changeWindowTypeAndRemember:NO];
  684.     
  685.     if (stoleActivation) 
  686.     {
  687.         if (oldActiveApp) [NXApp activate:oldActiveApp];
  688.         else [NXApp deactivateSelf];
  689.     }
  690.  
  691.     if (isHidden)
  692.     {
  693.         [NXApp hide:self];
  694.     }
  695.  
  696.     doingSaver = NO;
  697.  
  698.     return self;
  699. }
  700.  
  701. - appWillTerminate:sender
  702. {
  703.     [self normalMode];
  704.     return self;
  705. }
  706.  
  707. - appDidBecomeActive:sender
  708. {
  709.     id theMatrix;
  710.  
  711.     theMatrix = [viewSelectionBrowser matrixInColumn:0];
  712.     [theMatrix scrollCellToVisible:realViewIndex :0];
  713.     return self;
  714. }
  715.  
  716. - app:sender powerOffIn:(int)ms andSave:(int)aFlag
  717. {
  718.     return [NXApp terminate:self];
  719. }
  720.  
  721. - getPrioritySetting
  722. {
  723.     const char *ptr;
  724.     int val;
  725.  
  726.     [mySlider setMinValue: 0];
  727.     [mySlider setMaxValue: 10];
  728.     
  729.     ptr = NXGetDefaultValue([NXApp appName], "priority");
  730.     if (ptr)
  731.     {
  732.         sscanf(ptr,"%d",&val);
  733.         if (val >= 0 && val <= 10) priority = val;
  734.         else priority = 4;
  735.     }
  736.     else priority = 4;
  737.     
  738.     [[mySlider cell] setIntValue:priority];
  739.     [[priorityLevel cell] setIntValue:priority];
  740.  
  741. //    use mach call rather than unix - mach lets me increase priority!
  742. //    setpriority(PRIO_PROCESS, 0, priority);
  743.     cthread_priority(cthread_self(), priority, FALSE);
  744.  
  745.     return self;
  746. }
  747.  
  748. - changeSliderValue:sender
  749. {
  750.     priority = [[mySlider cell] intValue];
  751.     [[priorityLevel cell] setIntValue:priority];
  752.     return self;
  753. }
  754.  
  755. - saveSliderValue
  756. {
  757.     char str[50];
  758. //    setpriority(PRIO_PROCESS, 0, priority);
  759.     cthread_priority(cthread_self(), priority, FALSE);
  760.  
  761.     sprintf(str,"%d", priority);
  762.     NXWriteDefault([NXApp appName], "priority", str);
  763.     return self;
  764. }
  765.  
  766. - windowWillResize:sender toSize:(NXSize *)frameSize
  767. {
  768.     if (frameSize->width < 100) frameSize->width = 100;
  769.     if (frameSize->height < 100) frameSize->height = 100;
  770.     return self;
  771. }
  772.  
  773. - windowWillClose:sender
  774. {
  775.     [windMatrix selectCellAt:NOWINDOW :0];
  776.     [self perform:@selector(changeWindowType:) with:self
  777.         afterDelay:1 cancelPrevious:YES];
  778.     return nil;
  779. }
  780.  
  781. BStimeval currentTimeInMs()
  782. {
  783.     struct timeval curTime;
  784.     gettimeofday (&curTime, NULL);
  785.     return (curTime.tv_sec) * 1000 + curTime.tv_usec / 1000;
  786. }
  787.  
  788. //
  789. //    Additional methods to handle a common image object for views.
  790. //    Lennart Lovstrad, Rank Xerox EuroPARC, August 1991.
  791. //
  792.  
  793. - setImageFromFile: (const char *) filename
  794. {
  795.     [image free];
  796.  
  797.     image = [[NXImage alloc] initFromFile: filename];
  798.     if (image == nil)
  799.     {
  800.         NXRunAlertPanel([NXApp appName], NXLocalString("Could not open %s",0,0),
  801.                 NULL, NULL, NULL, filename);
  802.         image = nil;
  803.         //return nil;    //can't return, image is invalid
  804.     }
  805.     
  806.     return [self commonImageInit];
  807. }
  808.  
  809. - setImageFromName: (const char *) name
  810. {
  811.     [image free];
  812.     image = [[NXImage alloc] initFromSection: name];
  813.     
  814.     return [self commonImageInit];
  815. }
  816.  
  817. - commonImageInit
  818. {
  819.     [imageView setImage: image];
  820.     [imageView display];
  821.  
  822.     if ([spaceView respondsTo:@selector(setImage:)])
  823.         [spaceView setImage: image];
  824.  
  825.     if ([self backingTypeForView:spaceView] != NX_BUFFERED)
  826.     {
  827.         [spaceView fillBoundsWithBlack];
  828.         [spaceView display];
  829.     }
  830.  
  831.     return self;
  832. }
  833.  
  834. - getImageFile
  835. {
  836.     const char *filename;
  837.  
  838.     filename = NXGetDefaultValue([NXApp appName], "imageFile");
  839.     if (filename)
  840.         [self setImageFromFile: filename];
  841.     else [self setImageFromName: "defaultImage"];
  842.  
  843.     return self;
  844. }
  845.  
  846. - setImageFileFrom: sender
  847. {
  848.     id openPanel = [OpenPanel new];
  849.     const char *fileTypes[] = {"tiff", "eps", NULL};
  850.     
  851.     if ([openPanel runModalForTypes: fileTypes])
  852.     {
  853.         [self setImageFromFile: [openPanel filename]];
  854.         NXWriteDefault([NXApp appName], "imageFile", [openPanel filename]);
  855.     }
  856.  
  857.     [spaceView display];    //don't know why this is necessary...
  858.  
  859.     return self;
  860. }
  861.  
  862. // This should return a float between 0 and 1
  863. float frandom()
  864. {
  865.     float val = (random() & 0x7fffffff);
  866.     val /= 0x7fffffff;
  867.     return val;
  868. }
  869.  
  870. float randBetween(float a, float b)
  871. {
  872.     float val, scale, t;
  873.  
  874.     if (a > b)
  875.     {    t = a; a = b; b = t;
  876.     }
  877.     
  878.     scale = (b-a);
  879.     val = scale * frandom();
  880.     return (a + val);
  881. }
  882.  
  883. @end
  884.